var express = require('express');
var router = express.Router();
var config = require('../config');
const fs = require('fs')
const path = require('path');
const { spawn } = require('child_process');

var task = [];

function sendWs(req, data) {
  req.wss.clients.forEach((client) => {
    if (client.readyState === 1) {
      client.send(JSON.stringify(data));
    }
  });
}

router.get('/', function (req, res, next) {
  // res.render('index', { title: 'Ydownload' });
  res.sendFile(path.join(__dirname, '../views/sidepanel.html'));
});


router.get('/downloading', function (req, res) {
  var list = task.filter(obj => obj.status <= 1)
  res.json({ code: 0, msg: 'success', data: list });
});

router.get('/downloaded', function (req, res) {
  var list = task.filter(obj => obj.status > 1)
  res.json({ code: 0, msg: 'success', data: list });
});

router.get('/cancel', function (req, res) {
  const fileName = req.query.fileName;
  const index = task.findIndex(obj => obj.fileName == fileName)
  if (index !== -1) {
    task.splice(index, 1);
  }

  fs.unlink(`${config.downloadPath}/${fileName}.part`, (err) => {
    if (err) {
      console.error('Error deleting file:', err);
      return;
    }
  });

  res.json({ code: 0, msg: 'success'});
});

router.get('/delete', function (req, res) {
  const fileName = req.query.fileName;
  const index = task.findIndex(obj => obj.fileName = fileName)
  if (index !== -1) {
    task.splice(index, 1);
  }

  fs.unlink(`${config.downloadPath}/${fileName}`, (err) => {
    if (err) {
      console.error('Error deleting file:', err);
      return;
    }
  });

  fs.unlink(`${config.downloadPath}/${fileName}.part`, (err) => {
    if (err) {
      console.error('Error deleting file:', err);
      return;
    }
  });

  res.json({ code: 0, msg: 'success' });
});


router.get('/download', function (req, res) {
  const queryObject = req.query;
  var taskIndex = 0;

  var url = queryObject.url.replace("baidu", 'youtube')

  const command = 'yt-dlp';
  var args = ['--no-playlist', '-F', url];
  if (config.socks) {
    args = [
      '--proxy', config.socks,
      '--no-playlist',
      '-F', url
    ];
  }

  const ytDlpProcess = spawn(command, args);

  let outputBuffer = '';
  let read = false
  const info = [];
  let uid = '';
  const regex = /for\s(.*?):/

  ytDlpProcess.stdout.on('data', (data) => {

    console.log(`stdout: ${data.toString()}`);

    outputBuffer += data.toString();

    const lines = outputBuffer.split(/(\n|\r)/);
    outputBuffer = lines.pop();
    lines.forEach(line => {

      if (read) {
        const l = line.split('\|')[0];
        const d = l.split(/\s+/);
        if (d.length > 2) {

          if (d[1] == 'mp4') {
            var id = d[0];
            var ext = d[1];
            var resolution = d[2];
            var ch = d[4];

            if (resolution == 'audio') {
              if (!info.some(obj => obj.resolution == resolution)) {
                info.push({ id, ext, resolution,uid })
              }
            } else {
              if (!info.some(obj => obj.resolution == resolution && obj.ch == ch)) {
                info.push({ id, ext, resolution,uid, ch })
              }
            }
          }
        }
      }

      if (line.indexOf('-----------------------------') != -1) {
        read = true
      }else if(line.indexOf('[info] Available formats for')!=-1){
        const match = line.match(regex);
        if (match) {
          uid = match[1]
        }
      }

    });

  });

  ytDlpProcess.stderr.on('data', (data) => {
    console.error(`stderr: ${data.toString()}`);
  });

  ytDlpProcess.on('close', (code) => {
    info.sort((a, b) => {
      var x = a.ch? 1:0;
      var y = b.ch? 1:0;

      return y - x;
    });

    res.json({ code: 0, msg: 'success', data: info });
  });

  ytDlpProcess.on('error', (error) => {
    console.error(`Failed to start yt-dlp process: ${error.message}`);

  });

  //下载封面
  const regexes = [
    /.*\?v=([^&]+)/,
    /\/shorts\/(.*)$/,
  ];

  var videoId;
  for(var i = 0;i<regexes.length;i++){
    var match = url.match(regexes[i])
    if(match){
      videoId = match[1];
      break;
    }
  }
  
  if(videoId){
    const imgCommand = 'yt-dlp';
    var imgArgs = ['--no-playlist','--write-thumbnail','--skip-download','-P', config.downloadPath,'-o',videoId ,url];
    if (config.socks) {
      imgArgs = [
        '--proxy', config.socks,
        '--no-playlist',
        '--write-thumbnail', 
        '--skip-download',
        '-P', config.downloadPath,
        '-o',videoId,
        url
      ];
    }

    const imgProcess = spawn(imgCommand, imgArgs);
  
    imgProcess.stdout.on('data', (data) => {
      console.log(`imgProcess: ${data.toString()}`);
    });
  
    imgProcess.stderr.on('data', (data) => {
      console.error(`imgProcess: ${data.toString()}`);
    });
  
    imgProcess.on('close', (code) => {
      console.log(`imgProcess: ${code.toString()}`);
    });
  
    imgProcess.on('error', (error) => {
      console.error(`imgProcess Failed to start yt-dlp process: ${error.message}`);
    });
  }

});

router.post('/download', function (req, res) {
  const url = req.body.url.replace("baidu", 'youtube');
  const formatId = req.body.formatId;
  const ext = req.body.ext;
  const uid = req.body.uid;
  const resolution = req.body.resolution;
  const fileName = `${uid}-${resolution}.${ext}`

  fs.mkdir(config.downloadPath, { recursive: true }, (err, path) => {
    if (err) {
      if (err.code === 'EEXIST') {
        console.log(`Directory already exists: ${path}`);
      } else {
        console.error(`Failed to create directory: ${path}`, err);
      }
    } else {
      console.log(`Directory created: ${path}`);
    }
  });

  // 定义要执行的命令和参数
  const command = 'yt-dlp';
  var args = ['--no-playlist','-f', formatId, '-P', config.downloadPath,'-o',fileName , url];
  if (config.socks) {
    args = [
      '--proxy', config.socks,
      '--no-playlist',
      '-f', formatId,
      '-P', config.downloadPath,
      '-o',fileName ,
      url
    ];
  }

  if(task.some(obj => obj.url == url && obj.formatId == formatId)){
    res.json({ code: 1, msg: 'task has already' });
    return;
  }

  task.push({ url, formatId, status: 0,fileName,uid })
  //websocket
  sendWs(req, { url, formatId, status: 0,fileName,uid })

  // 使用 spawn 创建子进程
  const ytDlpProcess = spawn(command, args);

  let outputBuffer = '';

  const regexes = [
    /\[download\]\s+(.*?)\s+of\s+(.*?)\s+at\s+(.*?)\s+ETA.*/,
    /\[download\]\s+(.*?)\s+of\s+([\d\.]+[a-zA-Z]+)/,
    /\[download\]\s+(.*?)\s+of\s+([\d\.]+[a-zA-Z]+)\s+in\s+.*at\s+(.*)/,
  ];

  ytDlpProcess.stdout.on('data', (data) => {
    console.log(`stdout: ${data.toString()}`);

    outputBuffer += data.toString();

    const lines = outputBuffer.split(/(\n|\r)/);
    outputBuffer = lines.pop();
    lines.forEach(line => {

      for (let i = 0; i < regexes.length; i++) {
        const regex = regexes[i];
        const match = line.match(regex);
        if (match) {

          const t = task.find(obj => obj.url == url && obj.formatId == formatId)

          if(!t){
            ytDlpProcess.kill(); 
            break; 
          }

          if (i == 0) {
            const prog = match[1];
            const size = match[2];
            const speed = match[3];
            
            t.prog = prog;
            t.size = size;
            t.speed = speed;
            t.status = 1;

            //websocket
            sendWs(req, t)
          }else if(i == 1){
            const size = match[2];
            t.size = size;
            t.status = 1;

            //websocket
            sendWs(req, t)
          }else if(i == 2){
            const prog = match[1];
            const size = match[2];
            const speed = match[3];
            
            t.prog = prog;
            t.size = size;
            t.speed = speed;
            t.status = 1;
            //websocket
            sendWs(req, t)
          }

          break;  
        }

      }

    });
  });

  ytDlpProcess.stderr.on('data', (data) => {
    console.error(`stderr: ${data.toString()}`);
  });

  ytDlpProcess.on('close', (code) => {
    //websocket
    const t = task.find(obj => obj.url == url && obj.formatId == formatId);
    if(t){
      t.status = 2;
      sendWs(req, t);
    }
   
  });

  ytDlpProcess.on('error', (error) => {
    console.error(`Failed to start yt-dlp process: ${error.message}`);
    //websocket
    const t = task.find(obj => obj.url == url && obj.formatId == formatId);
    t.status = 3;
    sendWs(req, t);
  });

  res.json({ code: 0, msg: 'success' });
});

module.exports = router;
